// Package ast 实现了一个抽象语法树
//
// # 创建抽象语法树
//
// 创建抽象语法树推荐使用 [pkg/gitee.com/u-language/u-language/ucom/parser] 提供的简便函数
//
// 从词法分析结果创建抽象语法树，只需要调用 [NewTree]
//
// 如果要进行错误处理请自行使用 [pkg/gitee.com/u-language/u-language/ucom/errcode]
//
// # 辅助语义检查
//   - 会检查符号是否和其他符号重名
//   - 会检查枚举值是否重名
//   - 会检查是否调用禁止调用的init或main函数
//   - 会检查非main包是否有main函数
package ast

import (
	"fmt"
	"path/filepath"
	"strconv"
	"strings"
	"sync/atomic"

	"gitee.com/u-language/u-language/ucom/data"
	"gitee.com/u-language/u-language/ucom/errcode"
	"gitee.com/u-language/u-language/ucom/internal/errutil"
	"gitee.com/u-language/u-language/ucom/internal/utils"
	"gitee.com/u-language/u-language/ucom/lex"
)

var Deferfunc func() = utils.Deferfunc

// 节点接口，代表一个抽象语法树节点
type Node interface {
	String() string
	C(buf *strings.Builder)
}

// 表达式接口，代表一个表达式
type Expr interface {
	Node
	expr()
}

// FuncName 表示抽象语法树节点，这个节点可以表示函数名
// 可能的类型是 [Object] [Objects]
type FuncNameNode interface {
	Node
	// FuncName 返回人类可读的函数名表示，对于选择器，返回的只应该用于调试
	FuncName() string
}

type GetImport interface {
	//导入表
	GetImportTable() *Sbt
	//自己及依赖导入的包
	GerImportPackage() *map[string]*Package
	//自己导入的包
	GetImportLoacl() *[]data.IsItARecursiveType
}

type CType interface {
	CType(buf *strings.Builder)
}

var _ CType = (*Object)(nil)
var _ CType = (*Objects)(nil)

var _ GetImport = (*Tree)(nil)

// 一个抽象语法树
type Tree struct {
	//自己导入的包
	ImportLoacl *[]data.IsItARecursiveType
	//是否有自动是否块
	IsHaveAutoFree *atomic.Bool
	//符号表
	Sbt *Sbt
	//错误处理上下文
	errctx *errcode.ErrCtx
	//自己及依赖导入的包
	ImportPackage *map[string]*Package
	//是否有init函数
	IsInitFunc *atomic.Bool
	//变量初始化表
	VarInitTable_File *VarInitTable
	//在自动是否块被调用的函数名
	InAutoFreeFuncCallName *data.RemoveDupStrck[FuncNameNode]
	//导入表
	ImportTable *Sbt
	//泛型表
	GenericTable *Sbt
	//泛型实例化节点
	GenInstNodes *Sbt
	//包名
	PackageName string
	//文件名称
	Filename string
	//所有节点
	Nodes       []Node
	importLoacl []data.IsItARecursiveType
	//C代码的头文件包含的节点
	CHeaderFile *data.Slice[CHeaderFile]
	//是否并发
	Thread bool
}

type CHeaderFile struct {
	// 目前可能的节点
	// - 常量节点
	// - 变量节点
	// - 结构体节点
	// - 函数节点
	// - 方法节点
	// - 枚举声明
	N CDecl
	//line 行数-1的值
	Line int
}

// NewTree 创建抽象语法树，从词法分析结果开始
//   - ft是词法分析结果
//   - errctx是错误处理上下文
//   - Thread控制是否并发
func NewTree(ft *lex.FileToken, errctx *errcode.ErrCtx, sbt *Sbt, ImportPackage *map[string]*Package) *Tree {
	const Thread = false
	stack := data.NewRemoveDupStrck[FuncNameNode](Thread)
	varInitTable := NewVarInitTable(Thread)
	tree := newTree(sbt, Thread, ft.File, errctx, new(atomic.Bool), &stack, NewSbt(Thread), nil, nil, new(atomic.Bool), NewSbt(Thread), NewSbt(Thread), &varInitTable, new(data.Slice[CHeaderFile]))
	tree.ImportPackage = ImportPackage
	tree.ImportLoacl, tree.Sbt.importPackage = &tree.importLoacl, tree.ImportPackage
	tree.GenericTable.isUseCount = true
	tree.Nodes = ParserNode(tree, ft.Value, tree.Sbt, ParserNodeState{Index: 0, End: 0, Ret: nil, FuncInfo: nil, InAutoFree: false})
	generateGenInst(tree, tree.FindTree)
	tree.errctx = nil //当词法分析结果被转换为抽象语法树后，错误处理上下文不需要了，不需要保留指针
	return tree
}

func newTree(sbt *Sbt, thread bool, filename string, errctx *errcode.ErrCtx, IsInitFunc *atomic.Bool, InAutoFreeFuncCallName *data.RemoveDupStrck[FuncNameNode], importTable *Sbt, ImportPackage *map[string]*Package, ImportLoacl *[]data.IsItARecursiveType, IsHaveAutoFree *atomic.Bool, GenericTable *Sbt, GenInstNodes *Sbt, VarInitTable_File *VarInitTable, CHeaderFile *data.Slice[CHeaderFile]) *Tree {
	tree := &Tree{
		Filename:          filename,
		Thread:            thread,
		errctx:            errctx,
		ImportPackage:     ImportPackage,
		ImportLoacl:       ImportLoacl,
		IsInitFunc:        IsInitFunc,
		Sbt:               sbt,
		GenericTable:      GenericTable,
		GenInstNodes:      GenInstNodes,
		VarInitTable_File: VarInitTable_File,
		CHeaderFile:       CHeaderFile,
	}
	tree.InAutoFreeFuncCallName, tree.ImportTable, tree.IsHaveAutoFree = InAutoFreeFuncCallName, importTable, IsHaveAutoFree
	return tree
}

// 报错
func (t *Tree) Panic(line *lex.Line, msg errcode.Msg, err ...errcode.ErrCode) {
	t.errctx.Panic(t.Filename, line.Linenum, msg, err...)
}

func (t *Tree) String() string {
	var buf strings.Builder
	buf.Grow(10)
	buf.WriteString("&ast.Tree{\n")
	buf.WriteString("Filename:")
	buf.WriteString(t.Filename)
	buf.WriteString(", \n")
	buf.WriteString("Nodes:")
	for i := 0; i < len(t.Nodes); i++ {
		if t.Nodes[i] == nil {
			buf.WriteString("<nil>")
			continue
		}
		buf.WriteString("\n")
		buf.WriteString(strconv.Itoa(i))
		buf.WriteString("\t")
		buf.WriteString(t.Nodes[i].String())
	}
	buf.WriteString("\n}\n")
	buf.WriteString(t.Sbt.String())
	buf.WriteString("import info:\n")
	buf.WriteString(t.ImportTable.String())
	buf.WriteString("\nGenInstNodes:\n")
	buf.WriteString(t.GenericTable.String())
	buf.WriteString("\n}\n")
	return buf.String()
}

// 缩写：overwrite identifier 缩写成 overwrite_ident
func (t *Tree) overwrite_ident() {
	vlen := len(t.Nodes)
	for i := 0; i < vlen; i++ {
		overwrite_ident_node(t, t.Nodes[i])
	}
}

func overwrite_ident_node(t *Tree, n Node) {
	if utils.IsNil(n) {
		return
	}
	switch n := n.(type) {
	//变量声明和常量声明不重写名字是因为在解析节点时已经重写过了
	case *ASSIGNNode:
		overwrite_ident_node(t, n.Dest)
		overwrite_ident_node(t, n.Src)
	case *Object:
		switch n.Kind {
		case SymbolObj, LeaObj, DerefObj:
			rewriteTypeName(t, &n.Name)
		}
	case *SelfOpStmt:
		overwrite_ident_node(t, n.Dest)
	case *OpExpr:
		overwrite_ident_node(t, n.Src1)
		overwrite_ident_node(t, n.Src2)
	case *Objects:
		if !t.ImportTable.haveImport(n.Slice[0].Name) && n.Slice[0].Kind != TypeObj { //如果不是导入符号同时不是类型
			n.Slice[0].Name = utils.GeneratePackageSymbol(t.PackageName, n.Slice[0].Name)
		}
	case *CallNode:
		if o, ok := n.FuncName.(*Object); ok {
			if _, yes := Builtin_func_info[o.Name]; !yes { //不是内置函数
				o.Name = utils.GeneratePackageSymbol(t.PackageName, o.Name)
			}
		} else if _, ok := n.FuncName.(*GenericInstantiation); ok {

		} else {
			overwrite_ident_node(t, n.FuncName.(*Objects))
		}
	case *IndexExpr:
		overwrite_ident_node(t, n.X)
		overwrite_ident_node(t, n.Index)
	case *Dereference:
		overwrite_ident_node(t, n.Value)
	}
}

// rewriteTypeName 重写类型名
func rewriteTypeName(t *Tree, typ *string) {
	if (*typ)[0] == '&' {
		*typ = (*typ)[1:]
		defer func() {
			*typ = "&" + *typ
		}()
	}
	if (*typ)[0] == '@' {
		*typ = (*typ)[1:]
		defer func() {
			*typ = "@" + *typ
		}()
	}
	_, ok := TypeEnumStrMap[*typ]
	if ok {
		return
	}
	*typ = utils.GeneratePackageSymbol(t.PackageName, *typ)
}

func (t *Tree) GetImportTable() *Sbt {
	return t.ImportTable
}

func (t *Tree) GerImportPackage() *map[string]*Package {
	return t.ImportPackage
}

func (t *Tree) GetImportLoacl() *[]data.IsItARecursiveType {
	return t.ImportLoacl
}

func (t *Tree) FindTree(file string) *Tree {
	if file == t.Filename {
		return t
	}
	fileDir := filepath.Dir(file)
	for _, v := range *t.ImportPackage {
		if v.Dir == fileDir {
			return v.FindTree(file)
		}
	}
	panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未找到 %s 的抽象语法树", file)))
}
